<?php
namespace fast;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Yansongda\Pay\Log;
use Yansongda\Pay\Pay as Payhanld;


class Pay
{
    protected $config;
    protected $money=0;
    protected $subject='订单支付';
    protected $out_trade_no;
    protected $type;
    protected $openid;  //JSAPI支付必须传openid
    function __construct($config=[])
    {
        $this->config=self::getConfig();
        $this->setConfig($config);
    }

    function setConfig($config=[]){
        if($config){
            $this->config=array_merge($this->config,$config);
        }

        if(empty($this->config['alipay']['ali_public_key']) && !empty($this->config['alipay']['ali_public']) && is_file($this->config['alipay']['ali_public'])){
            $this->config['alipay']['ali_public_key']=trim(file_get_contents($this->config['alipay']['ali_public']));
            unset($this->config['alipay']['ali_public']);
        }
        if(empty($this->config['alipay']['private_key']) && !empty($this->config['alipay']['private']) && is_file($this->config['alipay']['private'])){
            $this->config['alipay']['private_key']=trim(file_get_contents($this->config['alipay']['private']));
            unset($this->config['alipay']['private']);
        }
        return $this;

    }

    function config(){
        return $this->config;
    }

    function money($money)
    {
        $this->money=abs(floatval($money));
        return $this;
    }

    function subject($str){
        $this->subject=$str;
        return $this;
    }

    function outTradeNo($outid){
        $this->out_trade_no=$outid;
        return $this;
    }

    function wechat(){
        $this->type='wechat';
        return $this;
    }

    function alipay(){
        $this->type='alipay';
        return $this;
    }

    function openid($openid){
        $this->openid=$openid;
        return $this;
    }

    function __call($name, $arguments)
    {
        // TODO: Implement __call() method.
        $names=[
            'wechat'=>['mp','miniapp','wap','scan','pos','app','transfer','redpack','groupRedpack'],
            'alipay'=>['web','wap','app','pos','scan','transfer','mini']
        ];
        $this->check();

        if(in_array($name,$names[$this->type])){
            if($this->type=='wechat'){
                $order = [
                    'out_trade_no' => $this->out_trade_no,
                    'total_fee' => $this->money*100,
                    'body' => $this->subject,
                ];
                if(!empty($this->openid)){ //JSAPI支付必须传openid
                    $order['openid']=$this->openid;
                }
                $pay = Payhanld::wechat($this->config['wechat'])->$name($order);
                \think\Log::info(json_encode($pay));
                if($pay instanceof JsonResponse || $pay instanceof Response){
                    $content=$pay->getContent();
                    if($content){
                        return json_decode($content,true);
                    }
                    return false;
                }

                return $pay;
            }
            if($this->type=='alipay'){
                $order = [
                    'out_trade_no' => $this->out_trade_no,
                    'total_amount' => $this->money,
                    'subject' => $this->subject,
                ];
                $pay = Payhanld::alipay($this->config['alipay'])->$name($order);
                return $pay->getContent();
            }
        }
    }

    protected function check(){
        if(empty($this->type)){
            throw new \Exception('未知的支付类型');
        }

        if(empty($this->out_trade_no)){
            throw new \Exception('未知的支付ID');
        }

    }

    function refund($type='app',$orderTotalFee=0){
        $this->check();
        $status=false;
        $trade_no='';
        if($this->type=='wechat'){
            if(empty($orderTotalFee)){
                $orderTotalFee=$this->money;
            }
            $order = [
                'out_trade_no' => $this->out_trade_no,
                'out_refund_no' => time().rand(100,999),  //退款单号，多次退款时不能重复
                'total_fee' => $orderTotalFee*100, //这里是订单金额，单位是分
                'refund_fee' => $this->money*100, //申请退款金额,不能大于订单金额，单位是分
                'refund_desc' => $this->subject,
                'type' => $type, //手机app是app 小程序是miniapp 公众号不要
                'refund_account'=>'REFUND_SOURCE_RECHARGE_FUNDS'  //使用余额退款,否则不要
            ];
            $pay = Payhanld::wechat($this->config['wechat'])->refund($order);
            $ret=$pay->toArray();
            $status=$ret['return_code']=='SUCCESS';
            $trade_no=$ret['transaction_id'];
        }elseif($this->type='alipay'){
            $order = [
                'out_trade_no' => $this->out_trade_no,
                'refund_amount' => $this->money,
            ];
            $pay = Payhanld::alipay($this->config['alipay'])->refund($order);
            $ret=$pay->toArray();
            $status=$ret['code']==10000;
            $trade_no=$ret['trade_no'];
        }
        return [
            'status'=>$status,
            'trade_no'=>$trade_no
        ];
    }

    function notify($callback){
        if($this->type=='wechat'){
            $pay = Payhanld::wechat($this->config['wechat']);
            $data = $pay->verify();
            $ret=$data->all();
            Log::debug('Wechat notify',$ret );
            $out=isset($ret['out_trade_no'])?$ret['out_trade_no']:0;
            if($out){
                $notify= [
                    'out_trade_no'=>$ret['out_trade_no'],
                    'status'=>$ret['return_code'] == 'SUCCESS'?true:false,
                    'notify_no'=>$ret['transaction_id'],
                    'money'=>$ret['total_fee']/100,
                    'appid'=>$ret['appid'],
                    'mch_id'=>$ret['mch_id'],
                    'type'=>'wechat',
                ];
            }else{
                throw new \Exception('未知out_trade_id');
            }
        }elseif($this->type=='alipay'){
            $alipay = Payhanld::alipay($this->config['alipay']);
            $data = $alipay->verify();
            $ret=$data->all();
            Log::debug('Alipay notify',$ret);
            $out=isset($ret['out_trade_no'])?$ret['out_trade_no']:0;
            if($out){
                $notify= [
                    'out_trade_no'=>$out,
                    'status'=>$ret['trade_status']=='TRADE_SUCCESS'?true:false,
                    'notify_no'=>$ret['trade_no'],
                    'money'=>$ret['buyer_pay_amount'],
                    'appid'=>$ret['app_id'],
                    'mch_id'=>0,
                    'type'=>'alipay',
                ];
            }else{
                throw new \Exception('未知out_trade_id');
            }
        }else{
            throw new \Exception('未知的支付类型');
        }

        if($notify){
            call_user_func_array($callback,['notify'=>$notify]);
        }
        return $pay->success()->send();
    }

    static protected function getConfig(){
        return [
            'alipay'=>[
                'app_id' => '',
                'notify_url' =>\think\Url::build('api/notify/alipay','',false,true),
                // 加密方式： **RSA2**
                'ali_public'=>ROOT_PATH.'data/alipay.public.key', //支付宝公钥保存文件
                'private'=>ROOT_PATH.'data/alipay.private.key', //商户私钥保存文件
                'log' => [
                    'file' => RUNTIME_PATH.'log/pay/alipay.log',
                    'level' => 'debug', //debug info notice warning error
                    'type' => 'single', //single=记录到单个文件  daily=以日期为单位的文件
                    'max_file' => 30, //当 type 为 daily 时有效，默认 30 天
                ],
                'http' => [
                    'timeout' => 5.0,
                    'connect_timeout' => 5.0,
                ],
                //'mode' => 'dev', //normal=正常模式 dev=将进入沙箱模式
            ],
            'wechat'=>[
                'app_id' => '',  //公众号支付
                'appid'=>'', //app支付
                'miniapp_id'=>'', //小程序支付
                'mch_id' => '', //商户id
                'key' => '',
                'notify_url' =>  \think\Url::build('api/notify/wechat','',false,true),
                'cert_client' =>ROOT_PATH. 'data/apiclient_cert.pem',
                'cert_key' => ROOT_PATH. 'data/apiclient_key.pem',
                'log' => [
                    'file' => RUNTIME_PATH.'log/pay/wechat.log',
                    'level' => 'debug',
                    'type' => 'single',
                    'max_file' => 30,
                ],
                'http' => [
                    'timeout' => 5.0,
                    'connect_timeout' => 5.0,
                ],
                //'mode' => 'dev',
            ]
        ];
    }
}